package com.cloudeye.bus.common;

import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.LambdaUtils;
import com.baomidou.mybatisplus.core.toolkit.support.ColumnCache;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.util.*;

/**
 * Created by lafangyuan on 2021/3/18.
 */
public abstract class BasicServiceImpl<M extends BasicMapper<T>, T> extends ServiceImpl<M,T> {



    /**
     * 租户标识
     */
    private static final String TENENT_KEY = "airport";

    /**
     * 用于单表查询，如果对象属性值不为空，则添加到where条件中：string-->like ,其他-->eq
     * @param t
     * @param isAsc
     * @param orderby
     * @return
     */
    public List<T> listLike(T t,boolean isAsc,String orderby){
        return  this.getBaseMapper().selectList(getLikeQueryWrapper(t).orderBy(true,isAsc,orderby));
    }
    /**
     * 用于单表查询，如果对象属性值不为空，则添加到where条件中：条件均为eq
     * @param t
     * @param isAsc
     * @param orderby
     * @return
     */
    public List<T> list(T t,boolean isAsc,String orderby){
        return  this.getBaseMapper().selectList(getEqQueryWrapper(t).orderBy(true,isAsc,orderby));
    }
    /**
     * 复合主键详情查询
     * @param entity
     * @return
     */
    public T selectByMultiId(T entity) {
        return this.getBaseMapper().selectOne(getIdQueryWrapper(entity));
    }

    /**
     * 复合主键单条删除
     *
     * @param entity
     * @return
     */
    public boolean removeByMultiId(T entity) {
        toUpperCase(entity);
        beforeRemove(entity);
        int count = this.getBaseMapper().delete(getIdQueryWrapper(entity));
        return count > 0;
    }

    /**
     * 删除前操作
     * @param entity
     */
    public void beforeRemove(T entity) {
    }

    /**
     * 复合主键批量删除
     * @param entitys
     * @return
     */
    public boolean removeBatchByMultiId(List<T> entitys) {
        List<QueryWrapper<T>> list = getIdWrapperByList(entitys);
        int count = 0;
        for (QueryWrapper<T> queryWrapper : list) {
            count += this.getBaseMapper().delete(queryWrapper);
        }
        return count > 0;
    }

    /**
     * 复合主键修改
     * @param entity
     * @return
     */
    public boolean updateByMultiId(T entity) {
        toUpperCase(entity);
        int count = this.getBaseMapper().update(entity, getIdQueryWrapper(entity));
        return count > 0;
    }


    /**
     * 复合主键批量修改
     * @param entitys
     * @return
     */
    public boolean updateBatchByMultiId(List<T> entitys) {
        List<QueryWrapper<T>> list = getIdWrapperByList(entitys);
        int count = 0;
        for (int i = 0; i < list.size(); i++) {
            count += this.getBaseMapper().update(toUpperCase(entitys.get(i)), list.get(i));
        }
        return count > 0;
    }

    @Override
    public boolean save(T entity) {
        toUpperCase(entity);
        initAirportCode(entity);
        int count = checkUnique(entity);
        if(count>0){
           throw new DuplicateKeyException("存在相同数据");
        }
        boolean flag =  super.save(entity);
        return flag;
    }

    private T toUpperCase(T t){
        List<Field> fields = getWrapperField(t);
        for (Field f : fields) {
            try {
                if(f.getAnnotation(UpperCase.class)!=null&&f.getType()==String.class){
                    f.setAccessible(true);
                    if (f.get(t) == null || "".equals(String.valueOf(f.get(t)))) {
                        continue;
                    }
                    if(f.get(t)!=null&&f.getAnnotation(UpperCase.class)!=null){
                        String value = f.get(t).toString().toUpperCase();
                        f.set(t,value);
                    }
                }
            } catch (IllegalAccessException e) {
                log.error(e.getMessage());
                continue;
            }
        }
        return t;
    }
    public int checkUnique(T entity){
        return count(getIdQueryWrapper(entity));
    }
    public QueryWrapper<T> getEqQueryWrapper(T t){
        initAirportCode(t);
        QueryWrapper<T> queryWrapper = new QueryWrapper();
        List<Field> fields = getWrapperField(t);
        Map<String, ColumnCache> columnMap = LambdaUtils.getColumnMap(t.getClass());
        for (Field f : fields) {
            try {
                f.setAccessible(true);
                if (f.get(t) == null || "".equals(String.valueOf(f.get(t)))) {
                    continue;
                }
                Object value = f.get(t);
                if(value!=null&&f.getAnnotation(UpperCase.class)!=null){
                    value = f.get(t).toString().toUpperCase();
                }
                ColumnCache columnCache = columnMap.get(LambdaUtils.formatKey(f.getName()));
                Assert.notNull(columnCache,"getEqQueryWrapper:未获取到["+t.getClass()+"]对象的属性["+f.getName()+"]");
                queryWrapper.eq(columnCache.getColumn(), value);
            } catch (IllegalAccessException e) {
                log.error(e.getMessage());
                continue;
            }
        }
        return queryWrapper;
    }
    public QueryWrapper<T> getIdQueryWrapper(T t){
        initAirportCode(t);
        QueryWrapper<T> queryWrapper = new QueryWrapper();
        List<Field> fields = getWrapperField(t);
        for (Field f : fields) {
            TableMultiId tableMultiId = f.getAnnotation(TableMultiId.class);
            if (tableMultiId != null) {
                f.setAccessible(true);
                try {
                    Object value = f.get(t);
                    if(value!=null&&f.getAnnotation(UpperCase.class)!=null){
                        value = f.get(t).toString().toUpperCase();
                    }
                    queryWrapper.eq(tableMultiId.value(), value);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }

        }
        return queryWrapper;
    }

    /**
     * 分页查询
     * @param reqPage
     * @return
     */
    public Page<T> queryByPage(ReqPage<T> reqPage) {
        Page<T> page = new Page<>(reqPage.getCurrent(),reqPage.getSize());
        this.page(page,getPageQueryWrapper(reqPage.getData()));
        return page;
    }

    /**
     * 默认分页使用精确查询
     * @param t
     * @return
     */
    public QueryWrapper<T> getPageQueryWrapper(T t){
        return getEqQueryWrapper(t);
    }
    public int count(T t){
        return this.count(getEqQueryWrapper(t));
    }
    public QueryWrapper<T> getLikeQueryWrapper(T t){
        initAirportCode(t);
        QueryWrapper<T> queryWrapper = new QueryWrapper();
        List<Field> fields = getWrapperField(t);
        Map<String, ColumnCache> columnMap = LambdaUtils.getColumnMap(t.getClass());
        for (Field f : fields) {
            try {
                f.setAccessible(true);
                if (f.get(t) == null || "".equals(String.valueOf(f.get(t)))) {
                    continue;
                }
                ColumnCache columnCache = columnMap.get(LambdaUtils.formatKey(f.getName()));
                Assert.notNull(columnCache,"getEqQueryWrapper:未获取到["+t.getClass()+"]对象的属性["+f.getName()+"]");
                if(f.getType()==String.class){
                    //租户字段使用精确查询
                    Object value = f.get(t);
                    if(f.getAnnotation(UpperCase.class)!=null){
                       value = f.get(t).toString().toUpperCase();
                    }
                    if(f.getName().equalsIgnoreCase(TENENT_KEY)&& f.getAnnotation(TableMultiId.class)!=null){
                        queryWrapper.eq(columnCache.getColumn(), value);
                    }else {
                        queryWrapper.like(columnCache.getColumn(), value);
                    }
                }else {
                    queryWrapper.eq(columnCache.getColumn(), f.get(t));
                }

            } catch (IllegalAccessException e) {
                log.error(e.getMessage());
                continue;
            }
        }
        return queryWrapper;
    }

    private List<Field> getWrapperField(T t){
        List<Field> fields = new ArrayList<>();
        for (Class clazz = t.getClass(); clazz != Object.class; clazz = clazz.getSuperclass()) {
            fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
        }
        return  fields;
    }
    /**
     * 组装联合主键的条件列表
     * @param entitys
     * @return
     */
    private List<QueryWrapper<T>> getIdWrapperByList(List<T> entitys) {
        List<QueryWrapper<T>> list = Lists.newArrayList();
        if (CollectionUtils.isEmpty(entitys)) {
            return null;
        }
        Field[] fields = entitys.get(0).getClass().getDeclaredFields();
        entitys.stream().forEach(entity -> {
            QueryWrapper<T> queryWrapper = new QueryWrapper();
            initAirportCode(entity);
            for (Field field : fields) {
                TableMultiId tableMultiId = field.getAnnotation(TableMultiId.class);
                if (tableMultiId != null) {
                    field.setAccessible(true);
                    try {
                        Object value = field.get(entity);
                        if(value!=null&&field.getAnnotation(UpperCase.class)!=null){
                            value = field.get(entity).toString().toUpperCase();
                        }
                        queryWrapper.eq(tableMultiId.value(), value);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
            list.add(queryWrapper);
        });
        return list;
    }

    /**
     * 根据url绑定机场三字码
     * @param t
     */
    public void initAirportCode(T t){
        if(t instanceof TenantData){
            TenantData data = (TenantData) t;
            //TODO: 先写死
            data.setAirport("XIY");
        }
    }


}
